#!/usr/bin/ruby
if ARGV.length != 2
  puts <<HELP
Usage:
  #{__FILE__} config.yml target
HELP
  exit
end
CONFIGFILE = ARGV[0]
TYPE       = ARGV[1]

require 'yaml'
CONFIG   = YAML.load File.open(CONFIGFILE,'r')
NOW      = "#{Time.now.strftime "%Y%m%d_%H%M%S%Z"}"
LOCAL_DEST = (CONFIG['local_destination'] || "/var/backup")+"/#{TYPE}/#{NOW}"
ZIP_NAME = "#{CONFIG[TYPE]['prefix']}_#{TYPE}_#{NOW}.tgz"
FTP_DEST = "backup"

def log msg,options={},&block
  puts "[#{Time.now}] #{TYPE} #{msg}"
  block.call if block_given?
  puts "[#{Time.now}] #{TYPE} #{msg} end" if options[:end]
end

require 'fileutils'
include FileUtils
def copy
  mkdir_p LOCAL_DEST
  targets = CONFIG[TYPE].select{|k,v|/^target\d*/ =~ k }.map{|k,v|v}.flatten! 1
  targets.each do|target|
    log "copy from #{target}"
    cp_r target, LOCAL_DEST
  end

  chdir LOCAL_DEST
  mysql = CONFIG[TYPE]['mysql']
  mysql['databases'].each do |db|
    log "database dump from #{db}"
    system "mysqldump -u#{mysql['user']} -p#{mysql['password']} #{db} > database_#{db}.sql"
  end if mysql
end

def process
  chdir "#{LOCAL_DEST}/.."
  rm_rf ZIP_NAME
  system "tar zcf #{ZIP_NAME} #{NOW}" 
  system "md5sum #{ZIP_NAME} > #{ZIP_NAME}.md5"
  size = File.size? ZIP_NAME
  log "#{ZIP_NAME} size is #{size} bytes (#{size/(1024**2)} MB)" if size and size >0
end

def upload_file src_path, dest_path,
                ftpinfo={ 'host'=>'','user'=>'','password'=>''}
  require 'net/ftp'
  Net::FTP.open(ftpinfo['host'],ftpinfo['user'],ftpinfo['password']) do |ftp|
    ftp.putbinaryfile src_path, dest_path
  end
end

def send
  ftps = CONFIG['destinations'].select{|n| n['ftp']}.map{|n|n['ftp']}
  ftps.each do |ftp|
    log "upload to #{ftp['host']}"
    upload_file "#{LOCAL_DEST}/../#{ZIP_NAME}.md5", "#{FTP_DEST}/#{ZIP_NAME}.md5", ftp
    upload_file "#{LOCAL_DEST}/../#{ZIP_NAME}", "#{FTP_DEST}/#{ZIP_NAME}", ftp
  end
end

def clean
  chdir "#{LOCAL_DEST}/.."
  rm_rf NOW
  list = Dir.glob("#{CONFIG[TYPE]['prefix']}_#{TYPE}*").sort
  list.pop CONFIG[TYPE]['history']*2
  rm_f list
end

begin
  log("copy,dump", :end=>true){copy}
  log("process(zip,md5,log)",:end=>true){process}
  log("send ftp",:end =>true){send}
    raise Exception.new 'asdf'
rescue => e
  if e.message.include? "Connection timed out"
    sleep 30
    log("retry send ftp",:end =>true){send}
  end
ensure
  log("clean"){clean}
end
